package com.austin.smp.service.Impl;

import com.austin.smp.common.api.ServerResponse;
import com.austin.smp.common.constant.Constant;
import com.austin.smp.common.util.BigDecimalUtil;
import com.austin.smp.common.util.DateTimeUtil;
import com.austin.smp.common.util.PropertiesUtil;
import com.austin.smp.dao.CartMapper;
import com.austin.smp.dao.OrderItemMapper;
import com.austin.smp.dao.OrderMapper;
import com.austin.smp.dao.ProductMapper;
import com.austin.smp.dao.ShippingMapper;
import com.austin.smp.entity.Cart;
import com.austin.smp.entity.Order;
import com.austin.smp.entity.OrderItem;
import com.austin.smp.entity.Product;
import com.austin.smp.entity.Shipping;
import com.austin.smp.service.OrderService;
import com.austin.smp.vo.OrderItemVO;
import com.austin.smp.vo.OrderProductVO;
import com.austin.smp.vo.OrderVO;
import com.austin.smp.vo.ShippingVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Random;


/**
 * @author austin
 * @since austin/6/21 11:04
 */

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    private CartMapper cartMapper;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private ShippingMapper shippingMapper;

    /**
     * 创建订单的逻辑：
     * 1.我们首先要知道查询购物车被勾选的商品，计算订单总价.
     * 2.生成订单.
     * 3.生成订单之后需要减少库存.
     * 4.最后清空购物车
     *
     * @param userId
     * @param shippingId
     * @return
     */
    @Override
    public ServerResponse createOrder(Integer userId, Integer shippingId) {
        //从购物车中获取数据，获取已经被勾选的商品
        List<Cart> cartList = cartMapper.selectCheckedCartByUserId(userId);

        //计算这个订单的总价
        ServerResponse serverResponse = this.getCartOrderItem(userId, cartList);
        if (!serverResponse.isSuccess()) {
            //返回orderItemList
            return serverResponse;
        }
        //将结果强转出来
        List<OrderItem> orderItemList = (List<OrderItem>) serverResponse.getData();
        //总金额
        BigDecimal payment = this.getOrderTotalPrice(orderItemList);
        //生成订单
        Order order = this.assembleOrder(userId, shippingId, payment);
        if (order == null) {
            return ServerResponse.createByErrorMessage("创建订单错误");
        }
        if (CollectionUtils.isEmpty(orderItemList)) {
            return ServerResponse.createByErrorMessage("购物车为空");
        }

        //订单号的赋值，在的同一个订单下的所有orderItem的orderNo是一样的
        for (OrderItem orderItem : orderItemList) {
            orderItem.setOrderNo(order.getOrderNo());
        }
        //mybatis批量插入
        orderItemMapper.batchInsert(orderItemList);
        //生成成功，数据库库存减少
        this.reduceProductStock(orderItemList);
        //清空购物车
        this.clearCart(cartList);

        //返回前端数据
        OrderVO orderVO = assembleOrderVO(order, orderItemList);
        return ServerResponse.createBySuccess(orderVO);
    }


    /**
     * getCartOrderItem()获取购物车子订单明细信息orderItem
     * <p>
     * 1.首先通过购物车列表遍历得到购物车cartItem
     * 2.再通过productId选出商品信息，跟数据库数据比较
     * 3.校验库存
     * 4.创建订单
     *
     * @param userId
     * @param cartList
     * @return 通过购物车对象，得到子订单明细，返回值是List的orderItem
     */
    public ServerResponse getCartOrderItem(Integer userId, List<Cart> cartList) {
        List<OrderItem> orderItemList = Lists.newArrayList();
        if (CollectionUtils.isEmpty(cartList)) {
            return ServerResponse.createByErrorMessage("购物车为空");
        }
        //校验购物车的数据，包括产品的状态和数量
        for (Cart cartItem : cartList) {
            OrderItem orderItem = new OrderItem();
            //检测购物车里的商品(状态，数量)
            Product product = productMapper.selectByPrimaryKey(cartItem.getProductId());
            if (product.getStatus() != Constant.ProductStatusEnum.ON_SALE.getCode()) {
                return ServerResponse.createByErrorMessage("产品" + product.getName() + "不是在线销售状态");
            }
            //校验库存
            if (cartItem.getQuantity() > product.getStock()) {
                return ServerResponse.createByErrorMessage("产品" + product.getName() + "库存不足");
            }
            //组装orderItem，该步骤是重点
            orderItem.setUserId(userId);
            orderItem.setProductId(product.getId());
            orderItem.setProductName(product.getName());
            orderItem.setProductImage(product.getMainImage());
            orderItem.setQuantity(cartItem.getQuantity());
            orderItem.setUnitPrice(product.getPrice());
            orderItem.setTotalPrice(BigDecimalUtil.mul(product.getPrice().doubleValue(), cartItem.getQuantity()));
            orderItemList.add(orderItem);
        }
        return ServerResponse.createBySuccess(orderItemList);
    }

    /**
     * 计算订单子明细中各个商品的总价 传参List<OrderItem> orderItemList
     *
     * @param orderItemList
     * @return
     */
    private BigDecimal getOrderTotalPrice(List<OrderItem> orderItemList) {
        BigDecimal payment = new BigDecimal("0");
        for (OrderItem orderItem : orderItemList) {
            //注意这里要将add的之后的结果赋值给payment再返回
            payment = BigDecimalUtil.add(payment.doubleValue(), orderItem.getTotalPrice().doubleValue());
        }
        return payment;
    }

    /**
     * 清空购物车
     *
     * @param cartList
     */
    private void clearCart(List<Cart> cartList) {
        for (Cart cart : cartList) {
            cartMapper.deleteByPrimaryKey(cart.getId());
        }
    }

    /**
     * 库存减少
     *
     * @param orderItemList
     */
    private void reduceProductStock(List<OrderItem> orderItemList) {
        for (OrderItem orderItem : orderItemList) {
            Product product = productMapper.selectByPrimaryKey(orderItem.getProductId());
            product.setStock(product.getStock() - orderItem.getQuantity());
            productMapper.updateByPrimaryKeySelective(product);
        }
    }

    /**
     * 创建订单成功的返回对象
     *
     * @param userId
     * @param shippingId
     * @param payment
     * @return
     */
    private Order assembleOrder(Integer userId, Integer shippingId, BigDecimal payment) {
        Order order = new Order();
        order.setOrderNo(this.generateOrderNo());   //orderNo采用当前时间 + new Random().nextInt(1000)的格式保存
        order.setStatus(Constant.OrderStatusEnum.NO_PAY.getCode());
        order.setPostage(0);    //邮费这里只考虑包邮，后面可以做扩展
        order.setPaymentType(Constant.PaymentTypeEnum.ONLINE_PAY.getCode());
        order.setPayment(payment);

        order.setUserId(userId);
        order.setShippingId(shippingId);

        //发货时间:在发货的业务逻辑上设置
        //付款时间:在付款的业务逻辑上设置
        int rowCount = orderMapper.insert(order);
        if (rowCount > 0) {
            return order;
        }
        return null;
    }


    /**
     * OrderVO类封装了返回创建订单的信息，包括订单信息，订单明细信息，地址信息，重要的订单返回对象
     * <p>
     * 传参：1.order  2.orderItemList
     *
     * @param order
     * @param orderItemList
     * @return
     */
    private OrderVO assembleOrderVO(Order order, List<OrderItem> orderItemList) {
        OrderVO orderVO = new OrderVO();
        orderVO.setOrderNo(order.getOrderNo());
        orderVO.setPayment(order.getPayment());
        orderVO.setPaymentType(order.getPaymentType());
        //通过code来获取对应的枚举PaymentTypeEnum，再通过枚举获取到value的值，用来返回给前端
        orderVO.setPaymentTypeDesc(Constant.PaymentTypeEnum.getByCode(order.getPaymentType()).getValue());
        orderVO.setPostage(order.getPostage());
        //通过code来获取对应的枚举OrderStatusEnum，再通过枚举获取到value的值，用来返回给前端
        orderVO.setPaymentType(order.getPaymentType());
        orderVO.setStatus(order.getStatus());
        orderVO.setStatusDesc(Constant.OrderStatusEnum.getByCode(order.getStatus()).getValue());
        orderVO.setShippingId(order.getShippingId());

        Shipping shipping = shippingMapper.selectByPrimaryKey(order.getShippingId());
        if (shipping != null) {
            orderVO.setReceiverName(shipping.getReceiverName());
            orderVO.setShippingVO(assembleShippingVO(shipping));
        }
        orderVO.setPaymentTime(DateTimeUtil.dateToStr(order.getPaymentTime()));
        orderVO.setDeliveryTime(DateTimeUtil.dateToStr(order.getDeliveryTime()));
        orderVO.setEndTime(DateTimeUtil.dateToStr(order.getEndTime()));
        orderVO.setCreateTime(DateTimeUtil.dateToStr(order.getCreateTime()));
        orderVO.setCloseTime(DateTimeUtil.dateToStr(order.getCloseTime()));

        orderVO.setImageHost(PropertiesUtil.getProperty("ftp.server.http.prefix"));

        //遍历传入的orderItemList，组装层orderItemVOList
        List<OrderItemVO> orderItemVOList = Lists.newArrayList();
        for (OrderItem orderItem : orderItemList) {
            OrderItemVO orderItemVO = assembleOrderItemVO(orderItem);
            orderItemVOList.add(orderItemVO);
        }
        orderVO.setOrderItemVOList(orderItemVOList);
        return orderVO;
    }

    public OrderItemVO assembleOrderItemVO(OrderItem orderItem) {
        OrderItemVO orderItemVO = new OrderItemVO();
        orderItemVO.setOrderNo(orderItem.getOrderNo());
        orderItemVO.setProductId(orderItem.getProductId());
        orderItemVO.setProductImage(orderItem.getProductImage());
        orderItemVO.setProductName(orderItem.getProductName());
        orderItemVO.setQuantity(orderItem.getQuantity());
        orderItemVO.setUnitPrice(orderItem.getUnitPrice());
        orderItemVO.setTotalPrice(orderItem.getTotalPrice());

        orderItemVO.setCreateTime(DateTimeUtil.dateToStr(orderItem.getCreateTime()));
        return orderItemVO;
    }

    private ShippingVO assembleShippingVO(Shipping shipping) {
        ShippingVO shippingVo = new ShippingVO();
        shippingVo.setReceiverName(shipping.getReceiverName());
        shippingVo.setReceiverAddress(shipping.getReceiverAddress());
        shippingVo.setReceiverProvince(shipping.getReceiverProvince());
        shippingVo.setReceiverCity(shipping.getReceiverCity());
        shippingVo.setReceiverDistrict(shipping.getReceiverDistrict());
        shippingVo.setReceiverPhone(shippingVo.getReceiverPhone());
        shippingVo.setReceiverZip(shipping.getZipCode());
        return shippingVo;
    }

    /**
     * orderNo生成方式
     *
     * @return
     */
    private long generateOrderNo() {
        long currentTime = System.currentTimeMillis();
        return currentTime + new Random().nextInt(1000);  //时间+[0,1000)之间的数即[0,999]
    }

    /**
     * 获取购物车中已选中的商品详情
     * 步骤：
     * 1.先获取购物车中商品的信息cartList
     * 2.通过cartList获取orderItemList
     * 3.将orderItem对象转换成orderItemVO返回
     *
     * @param userId
     * @return
     */
    @Override
    public ServerResponse getOrderCartProduct(Integer userId) {
        //1.先从购物车中获取购物商品信息
        List<Cart> cartList = cartMapper.selectCheckedCartByUserId(userId);
        ServerResponse serverResponse = this.getCartOrderItem(userId, cartList);
        if (!serverResponse.isSuccess()) {
            return serverResponse;
        }
        List<OrderItem> orderItemList = (List<OrderItem>) serverResponse.getData();

        BigDecimal payment = new BigDecimal("0");

        List<OrderItemVO> orderItemVOList = Lists.newArrayList();

        for (OrderItem orderItem : orderItemList) {
            payment = BigDecimalUtil.add(payment.doubleValue(), orderItem.getTotalPrice().doubleValue());
            orderItemVOList.add(assembleOrderItemVO(orderItem));
        }
        //封装返回OrderProduct对象
        OrderProductVO orderProductVO = new OrderProductVO();
        orderProductVO.setOrderItemVOList(orderItemVOList);
        orderProductVO.setProductTotalPrice(payment);
        orderProductVO.setImageHost(PropertiesUtil.getProperty("ftp.server.http.prefix"));

        return ServerResponse.createBySuccess(orderProductVO);
    }

    /**
     * 订单列表
     *
     * @param userId
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public ServerResponse<PageInfo> getOrderList(Integer userId, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Order> orderList = orderMapper.selectByUserId(userId);
        List<OrderVO> orderVOList = assembleOrderVOList(userId, orderList);
        PageInfo pageResult = new PageInfo(orderList);
        pageResult.setList(orderVOList);
        return ServerResponse.createBySuccess(pageResult);
    }

    /**
     * 组装orderVOList 由orderVO组成
     * <p>
     * 注意：OrderVO包括Order和OrderItem明细
     *
     * @param userId
     * @param orderList
     * @return
     */
    private List<OrderVO> assembleOrderVOList(Integer userId, List<Order> orderList) {
        List<OrderVO> orderVOList = Lists.newArrayList();
        for (Order order : orderList) {
            List<OrderItem> orderItemList = Lists.newArrayList();
            if (userId == null) {
                //管理员查询的时候 不需要传userId 用来给后台管理员使用，直接传和null就行
                orderItemList = orderItemMapper.getByOrderNo(order.getOrderNo());
            }
            orderItemList = orderItemMapper.getByOrderNoUserId(userId, order.getOrderNo());

            OrderVO orderVO = assembleOrderVO(order, orderItemList);
            orderVOList.add(orderVO);
        }
        return orderVOList;
    }

    /**
     * 获取订单的商品信息
     *
     * @param userId
     * @param orderNo
     * @return
     */
    @Override
    public ServerResponse<OrderVO> getOrderDetail(Integer userId, Long orderNo) {
        Order order = orderMapper.selectByUserIdOrderNo(userId, orderNo);
        if (order != null) {
            List<OrderItem> orderItemList = orderItemMapper.getByOrderNoUserId(userId, orderNo);
            OrderVO orderVO = assembleOrderVO(order, orderItemList);
            return ServerResponse.createBySuccess(orderVO);
        }
        return ServerResponse.createByErrorMessage("订单不存在");
    }

    /**
     * 取消订单
     *
     * @param userId
     * @param orderNo
     * @return
     */
    @Override
    public ServerResponse<String> cancel(Integer userId, Long orderNo) {
        Order order = orderMapper.selectByUserIdOrderNo(userId, orderNo);
        if (order == null) {
            return ServerResponse.createBySuccessMessage("该用户此订单不存在");
        }
        if (order.getStatus() != Constant.OrderStatusEnum.NO_PAY.getCode()) {
            return ServerResponse.createBySuccessMessage("此订单已付款，无法被取消");
        }
        Order orderUpdate = new Order();
        orderUpdate.setId(order.getId());
        orderUpdate.setStatus(Constant.OrderStatusEnum.CANCELED.getCode()); //更新商品为取消状态
        int rowCount = orderMapper.updateByPrimaryKeySelective(orderUpdate);
        if (rowCount > 0) {
            return ServerResponse.createBySuccessMessage("取消订单成功");
        }
        return ServerResponse.createByErrorMessage("取消订单失败");
    }


    /*-------------------------------后台---------------------------------*/

    @Override
    public ServerResponse<PageInfo> manageList(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Order> orderList = orderMapper.selectAllOrder();

        List<OrderVO> orderVOList = assembleOrderVOList(null, orderList);
        PageInfo pageResult = new PageInfo(orderList);
        pageResult.setList(orderVOList);
        return ServerResponse.createBySuccess(pageResult);
    }

    /**
     * 后台查询商品，这里虽然做精确匹配查询，只传orderNo的，但是为了后期支持模糊查询作准备，这里选择将结果分页
     */
    @Override
    public ServerResponse<PageInfo> manageSearch(Long orderNo, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        //先查询到该订单
        Order order = orderMapper.selectByOrderNo(orderNo);
        //再查询订单明细子表
        if (order != null) {
            List<OrderItem> orderItemList = orderItemMapper.getByOrderNo(orderNo);
            //3.封装成orderVO对象返回
            OrderVO orderVO = assembleOrderVO(order, orderItemList);
            PageInfo pageResult = new PageInfo();
            pageResult.setList(Lists.newArrayList(orderVO));
            return ServerResponse.createBySuccess(pageResult);
        }
        return ServerResponse.createByErrorMessage("订单不存在");
    }

    @Override
    public ServerResponse<OrderVO> manageDetail(Long orderNo) {
        Order order = orderMapper.selectByOrderNo(orderNo);
        if (order != null) {
            List<OrderItem> orderItemList = orderItemMapper.getByOrderNo(orderNo);
            OrderVO orderVO = assembleOrderVO(order, orderItemList);
            return ServerResponse.createBySuccess(orderVO);
        }
        return ServerResponse.createByErrorMessage("订单不存在");
    }

    @Override
    public ServerResponse<String> manageSendGoods(Long orderNo) {
        Order order = orderMapper.selectByOrderNo(orderNo);
        if (order != null) {
            if (order.getStatus() == Constant.OrderStatusEnum.PAID.getCode()) {
                order.setStatus(Constant.OrderStatusEnum.SHIPPED.getCode());
                order.setDeliveryTime(new Date());
                orderMapper.updateByPrimaryKeySelective(order);
                return ServerResponse.createByErrorMessage("订单发货成功");
            }
        }
        return ServerResponse.createByErrorMessage("订单不存在");
    }

    @Override
    public void closeOrder(int hours) {
        //前hour小时的订单
        Date closeDateTime = DateUtils.addHours(new Date(), -hours);
        List<Order> orderList = orderMapper.selectOrderStatusByCreateTime(Constant.OrderStatusEnum.NO_PAY.getCode(), DateTimeUtil.dateToStr(closeDateTime));
        for (Order order : orderList) {
            List<OrderItem> orderItemList = orderItemMapper.getByOrderNo(order.getOrderNo());
            for (OrderItem orderItem : orderItemList) {
                //拿到即将要被关闭商品的和数量：一定要用主键where条件，防止锁表，同时必须支持MySQL的InnoDB引擎
                Integer stock = productMapper.selectStockByProductId(orderItem.getProductId());
                //考虑到已生成订单里的商品已被删除，这时候就不必更新了
                if (stock == null) {
                    continue;
                }
                Product product = new Product();
                product.setId(orderItem.getProductId());
                product.setStock(stock + orderItem.getQuantity());
                productMapper.updateByPrimaryKeySelective(product);
            }
            orderMapper.closeOrderByOrderId(order.getId());
            log.info("关闭订单orderNo:{}", order.getOrderNo());
        }
    }

    public static void main(String[] args) {
        //使用System.currentTimeMillis();获取的是1970-1-01到现在当前时刻的时间距离，单位为毫秒
        long millis = System.currentTimeMillis();
        //在通过随机生成0-1000的数组成订单号的生成规则
        System.out.println(millis + new Random().nextInt(1000));
    }
}
